package apollo

import (
	"encoding/json"
	"errors"
	"fmt"
	"gf-xb-api/internal/consts"
	"strconv"
	"strings"
	"sync"

	"github.com/apolloconfig/agollo/v4"
	apolloConfig "github.com/apolloconfig/agollo/v4/env/config"
	"github.com/gogf/gf/contrib/config/apollo/v2"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gctx"
)

var apolloOnce sync.Once
var apolloInstance *agollo.Client
var config apollo.Config

// 注意：这里的init一定要在load_apollo.init()前面，否则获取不到apollo其他namespace的配置
func init() {

	var ctx = gctx.GetInitCtx()

	vAppId, err := g.Cfg().Get(ctx, consts.APOLLO_APPID)
	if err != nil {
		g.Log().Fatalf(ctx, `%+v`, err)
	}

	vIp, err := g.Cfg().Get(ctx, consts.APOLLO_IP)
	if err != nil {
		g.Log().Fatalf(ctx, `%+v`, err)
	}

	vCluster, err := g.Cfg().Get(ctx, consts.APOLLO_CLUSTER)
	if err != nil {
		g.Log().Fatalf(ctx, `%+v`, err)
	}

	vNamespaces, err := g.Cfg().Get(ctx, consts.APOLLO_NAMESPACES)
	if err != nil {
		g.Log().Fatalf(ctx, `%+v`, err)
	}

	// Create apollo Client that implements gcfg.Adapter.
	config = apollo.Config{
		AppID:         vAppId.String(),
		IP:            vIp.String(),
		Cluster:       vCluster.String(),
		NamespaceName: vNamespaces.String(),
	}
}

// GetInstance ... 获得apollo实例
func GetInstance() *agollo.Client {
	apolloOnce.Do(func() {
		client, err := agollo.StartWithConfig(func() (*apolloConfig.AppConfig, error) {
			return &apolloConfig.AppConfig{
				AppID:             config.AppID,
				Cluster:           config.Cluster,
				NamespaceName:     config.NamespaceName,
				IP:                config.IP,
				IsBackupConfig:    config.IsBackupConfig,
				BackupConfigPath:  config.BackupConfigPath,
				Secret:            config.Secret,
				SyncServerTimeout: config.SyncServerTimeout,
				MustStart:         config.MustStart,
			}, nil
		})

		if err != nil {
			panic(err)
		}

		apolloInstance = &client
	})

	return apolloInstance
}

// GetValue ... 获得值
func GetValue(namespace, key string) interface{} {

	if namespace == "" || key == "" {
		return nil
	}

	var client = GetInstance()
	val, err := (*client).GetConfigCache(namespace).Get(key)
	if err != nil {
		return nil
	}
	if val == nil {
		return nil
	}

	return val
}

// GetValueByNpWithKey ... 获得值 参数是 namespace:key
func GetValueByNpWithKey(npWithKey string) interface{} {

	if npWithKey == "" {
		return nil
	}

	splits := strings.Split(npWithKey, ":")
	if len(splits) < 2 {
		return nil
	}

	return GetValue(splits[0], splits[1])
}

// GetStringValue ... 获得字符串
func GetStringValue(npWithKey string) string {
	val := GetValueByNpWithKey(npWithKey)
	return fmt.Sprintf("%v", val)
}

// GetIntValue ... 获得整数
func GetIntValue(npWithKey string) *int {
	val := GetValueByNpWithKey(npWithKey)

	if iVal, ok := val.(int); ok {
		return &iVal
	} else if sVal, ok := val.(string); ok {
		iVal, err := strconv.Atoi(sVal)
		if err != nil {
			return nil
		}

		return &iVal
	}

	return nil
}

// GetTValue ... 获得泛型值
func GetTValue[T any](npWithKey string) *T {
	if npWithKey == "" {
		return nil
	}

	val := GetStringValue(npWithKey)
	if val == "" {
		return nil
	}

	var res T

	if e := json.Unmarshal([]byte(val), &res); e != nil {
		var ute *json.UnmarshalTypeError
		if errors.As(e, &ute) {
			fmt.Printf("UnmarshalTypeError %v - %v - %v\n", ute.Value, ute.Type, ute.Offset)
		}

		return nil
	}

	return &res
}

// GetTValueList ... 获得泛型值列表
func GetTValueList[T any](npWithKey string) *[]T {
	return GetTValue[[]T](npWithKey)
}
